#include "globalstates.h"
#define IS_SUCCESSFUL true
#define MSG_SUCCESS "Successfully set"
#define MSG_FAIL_INVALID_INPUT "Invalid input values!"

GlobalStates::GlobalStates()
{
    RGB.r = 0; RGB.g = 200; RGB.b = 0;

}

GlobalStates *GlobalStates::getInstance()
{
    static GlobalStates* inst=0;
    if(!inst)inst = new GlobalStates();
    return inst;
}


Result GlobalStates::setRGB(char R, char G, char B)
{
    RGB.r = R;
    RGB.g = G;
    RGB.b = B;
    return Result(IS_SUCCESSFUL, MSG_SUCCESS);

}

int GlobalStates::getScreenHeight()
{
    return screenHeight;
}

int GlobalStates::getScreenWidth()
{
    return screenWidth;
}

void GlobalStates::setScreenResolution(int w, int h)
{
    screenWidth = w;
    screenHeight = h;
}

colour GlobalStates::colorMask(colour &c){
    static const colour mask(0,0,255);
    return colour(c.r ^ mask.r , c.g ^ mask.g , c.b ^ mask.b );
}

Result GlobalStates::addVoxelToSelection(int i, int j, int k){
    RenderManager  *   rend = RenderManager::getInstance();
    if (rend->isVoxelDrawn(i, j, k)) {
        if (selection.find(vector3<int>(i, j, k))==selection.end()) {
            colour c = colorMask(rend->getVoxelColor(i, j, k));
            selection.insert(vector3<int>(i, j, k));
            rend->setVoxelColor(i, j, k, c);
            return Result(true, "Voxel selected");
        }
        return Result(false, "Voxel has already been inserted into selection");
    }
    return Result(false, "No voxel drawn");
}

Result GlobalStates::deleteVoxelFromSelection(int i, int j,int k){
    RenderManager   *  rend = RenderManager::getInstance();
    if (rend->isVoxelDrawn(i, j, k)) {
        if (selection.find(vector3<int>(i,j,k))!=selection.end()) {
            colour c = colorMask(rend->getVoxelColor(i, j, k));
            selection.erase(vector3<int>(i, j, k));
            rend->setVoxelColor(i, j, k, c);
            return Result(true, "Voxel deselected");
        }
        return Result(false, "Voxel is not in selection");
    }
    return Result(false, "No voxel drawn");
}

void GlobalStates::clearSelection(){
    RenderManager   *  rend = RenderManager::getInstance();
    if (!selection.empty()){
        for (set<vector3<int> >::iterator it = selection.begin(); it!=selection.end(); it++) {
            int i = (*it).x;
            int j = (*it).y;
            int k = (*it).z;
            colour c = colorMask(rend->getVoxelColor(i, j, k));
            rend->setVoxelColor(i, j, k, c);
        }
        selection.clear();
    }
}

bool GlobalStates::isSelectionEmpty(){
    return selection.empty();
}

bool GlobalStates::findInSelection(int i, int j, int k) {
    if (selection.find(vector3<int>(i, j, k))!=selection.end()) {
        return true;
    }
    else return false;
}

const set<vector3<int> > &GlobalStates::getSelection(){
    return selection;
}

Result GlobalStates::changeAllSelectedVoxelsColour(colour c){
    RenderManager   *  rend = RenderManager::getInstance();
    for (set<vector3<int> >::iterator it = selection.begin(); it!=selection.end(); it++) {
        int i = (*it).x;
        int j = (*it).y;
        int k = (*it).z;
        colour maskedColour = colorMask(c);
        rend->setVoxelColor(i, j, k, maskedColour);
    }
    return Result (true, "Colour of selected voxels changed");
}

bool GlobalStates::isInAcceptableRange(vector3<int> coords){
    if (coords.x < -WORLD_XSIZE*0.2 || coords.x > WORLD_XSIZE*1.2
            || coords.y < -WORLD_YSIZE*0.5 || coords.y > WORLD_YSIZE*1.2
            || coords.z < 0 || coords.z > WORLD_ZSIZE*1.2)
        return false;
    return true;
}

bool GlobalStates::isInAcceptableRange(FIXED_AXES axis, int number){
    switch(axis){
    case(XAXIS):
        if (number < -WORLD_XSIZE*0.2 || number > WORLD_XSIZE*1.2)
            return false;
        break;
    case(YAXIS):
        if (number < -WORLD_YSIZE*0.5 || number > WORLD_YSIZE*1.5)
            return false;
        break;
    case(ZAXIS):
        if (number < -WORLD_ZSIZE*0.5 || number > WORLD_ZSIZE*1.5)
            return false;
        break;
    }
    return true;
}


